1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include "referencecasting.hxx"
14 #include <clang/AST/Attr.h>
21 This is a compile-time checker.
23 Check for cases where we have
24 - two IDL interfaces A and B,
26 - we are converting a Reference<B> to a Reference<A>
28 Note that it generates the occasional false positive.
30 Also, it makes clang3.2 crash on about 4 files in the LO codebase.
31 I have logged a bug here:
32 http://llvm.org/bugs/show_bug.cgi?id=15902
35 ReferenceCasting::ReferenceCasting( CompilerInstance
& compiler
)
36 : FilteringPlugin( compiler
)
40 void ReferenceCasting::run()
42 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
46 // static void example_method()
48 // css::uno::Reference<B> b;
49 // css::uno::Reference<A>(b, css::uno::UNO_QUERY);
51 // Compiles to this AST:
52 // (CompoundStmt 0x205d430 </noel-extra1/libo-clang/compilerplugins/clang/noel1.cxx:17:1, line:20:1>
53 // (DeclStmt 0x20580a8 <line:18:5, col:32>
54 // (0x20530e0 "css::uno::Reference<B> refB =
55 // (CXXConstructExpr 0x2058078 <col:28> 'css::uno::Reference<B>':'class com::sun::star::uno::Reference<class B>''void(void)')"))
56 // (DeclStmt 0x205d418 <line:19:5, col:59>
57 // (0x2058310 "css::uno::Reference<A> refA =
58 // (CXXConstructExpr 0x205d3d8 <col:28, col:58> 'css::uno::Reference<A>':'class com::sun::star::uno::Reference<class A>''void (const class com::sun::star::uno::BaseReference &, enum com::sun::star::uno::UnoReference_Query)'
59 // (ImplicitCastExpr 0x205d3c0 <col:33> 'const class com::sun::star::uno::BaseReference' lvalue <NoOp>
60 // (ImplicitCastExpr 0x205d3a0 <col:33> 'class com::sun::star::uno::BaseReference' lvalue <DerivedToBase (BaseReference)>
61 // (DeclRefExpr 0x20582a0 <col:33> 'css::uno::Reference<B>':'class com::sun::star::uno::Reference<class B>' lvalue Var 0x20530e0 'refB' 'css::uno::Reference<B>':'class com::sun::star::uno::Reference<class B>')))
62 // (DeclRefExpr 0x2058398 <col:39, col:49> 'enum com::sun::star::uno::UnoReference_Query' EnumConstant 0x1831de0 'UNO_QUERY' 'enum com::sun::star::uno::UnoReference_Query'))")))
66 // static void example_method1(css::uno::Reference<A>)
69 // static void example_method2()
71 // css::uno::Reference<B> refB;
72 // example_method1(css::uno::Reference<A>(refB, css::uno::UNO_QUERY));
74 // Compiles to this AST:
75 // static void example_method1(css::uno::Reference<A>) (CompoundStmt 0x2a74ee8 </noel-extra1/libo-clang/compilerplugins/clang/noel1.cxx:17:1, line:18:1>)
76 // static void example_method2() (CompoundStmt 0x2a7a650 </noel-extra1/libo-clang/compilerplugins/clang/noel1.cxx:21:1, line:24:1>
77 // (DeclStmt 0x2a7a1a8 <line:22:5, col:32>
78 // (0x2a751e0 "css::uno::Reference<B> refB =
79 // (CXXConstructExpr 0x2a7a178 <col:28> 'css::uno::Reference<B>':'class com::sun::star::uno::Reference<class B>''void(void)')"))
80 // (ExprWithCleanups 0x2a7a638 <line:23:5, col:70> 'void'
81 // (CallExpr 0x2a7a570 <col:5, col:70> 'void'
82 // (ImplicitCastExpr 0x2a7a558 <col:5> 'void (*)(css::uno::Reference<A>)' <FunctionToPointerDecay>
83 // (DeclRefExpr 0x2a7a4d8 <col:5> 'void (css::uno::Reference<A>)' lvalue Function 0x2a6ff00 'example_method1' 'void (css::uno::Reference<A>)'))
84 // (CXXBindTemporaryExpr 0x2a7a618 <col:21, col:69> 'css::uno::Reference<A>':'class com::sun::star::uno::Reference<class A>' (CXXTemporary 0x2a7a610)
85 // (CXXConstructExpr 0x2a7a5d8 <col:21, col:69> 'css::uno::Reference<A>':'class com::sun::star::uno::Reference<class A>''void (const Reference<class A> &)' elidable
86 // (MaterializeTemporaryExpr 0x2a7a5c0 <col:21, col:69> 'const Reference<class A>':'const class com::sun::star::uno::Reference<class A>' lvalue
87 // (ImplicitCastExpr 0x2a7a5a8 <col:21, col:69> 'const Reference<class A>':'const class com::sun::star::uno::Reference<class A>' <NoOp>
88 // (CXXBindTemporaryExpr 0x2a7a4b8 <col:21, col:69> 'css::uno::Reference<A>':'class com::sun::star::uno::Reference<class A>' (CXXTemporary 0x2a7a4b0)
89 // (CXXTemporaryObjectExpr 0x2a7a460 <col:21, col:69> 'css::uno::Reference<A>':'class com::sun::star::uno::Reference<class A>''void (const class com::sun::star::uno::BaseReference &, enum com::sun::star::uno::UnoReference_Query)'
90 // (ImplicitCastExpr 0x2a7a448 <col:44> 'const class com::sun::star::uno::BaseReference' lvalue <NoOp>
91 // (ImplicitCastExpr 0x2a7a428 <col:44> 'class com::sun::star::uno::BaseReference' lvalue <DerivedToBase (BaseReference)>
92 // (DeclRefExpr 0x2a7a340 <col:44> 'css::uno::Reference<B>':'class com::sun::star::uno::Reference<class B>' lvalue Var 0x2a751e0 'refB' 'css::uno::Reference<B>':'class com::sun::star::uno::Reference<class B>')))
93 // (DeclRefExpr 0x2a7a398 <col:50, col:60> 'enum com::sun::star::uno::UnoReference_Query' EnumConstant 0x224ee20 'UNO_QUERY' 'enum com::sun::star::uno::UnoReference_Query'))))))))))
95 static const Type
* extractTemplateType(Expr
* cce
);
97 bool ReferenceCasting::VisitCXXConstructExpr( CXXConstructExpr
* cce
)
99 // don't bother processing anything in the Reference.h file. Makes my life easier when debugging this.
100 if( StringRef(compiler
.getSourceManager().getPresumedLoc( cce
->getSourceRange().getBegin() )).find( "Reference.h" ) != StringRef::npos
)
103 // look for calls to the Reference<T>(x,UNO_something) constructor
104 if( cce
->getConstructor()->getNameInfo().getName().getAsString() != "Reference" )
107 if( cce
->getNumArgs() != 2 )
110 // extract the type parameter passed to the template
111 const Type
* templateParamType
= extractTemplateType(cce
);
112 if ( !templateParamType
)
115 // extract the type of the first parameter passed to the constructor
116 Expr
* constructorArg0
= cce
->getArg(0);
117 if( !constructorArg0
)
120 // ignore the Reference(XInterface*,...) constructor
121 if( constructorArg0
->getType()->isPointerType() )
124 // drill down the expression tree till we hit the bottom
125 DeclRefExpr
* constructorSubArg2
;
126 Expr
* constructorArg0SubExpr
= constructorArg0
;
129 // if we've hit the member expression we want, break
130 constructorSubArg2
= dyn_cast
<DeclRefExpr
>( constructorArg0SubExpr
);
131 if( constructorSubArg2
)
133 CastExpr
* tmp1
= dyn_cast
<CastExpr
>( constructorArg0SubExpr
);
135 constructorArg0SubExpr
= tmp1
->getSubExpr();
138 MaterializeTemporaryExpr
* tmp2
= dyn_cast
<MaterializeTemporaryExpr
>( constructorArg0SubExpr
);
140 constructorArg0SubExpr
= tmp2
->GetTemporaryExpr();
143 CXXBindTemporaryExpr
* tmp3
= dyn_cast
<CXXBindTemporaryExpr
>( constructorArg0SubExpr
);
145 constructorArg0SubExpr
= tmp3
->getSubExpr();
148 CXXTemporaryObjectExpr
* tmp4
= dyn_cast
<CXXTemporaryObjectExpr
>( constructorArg0SubExpr
);
150 constructorArg0SubExpr
= tmp4
->getArg(0);
156 const Type
* tmp3
= extractTemplateType( constructorSubArg2
);
160 const RecordType
* templateParamRT
= dyn_cast
<RecordType
>( templateParamType
);
161 const RecordType
* constructorArgRT
= dyn_cast
<RecordType
>( tmp3
);
162 if( !templateParamRT
|| !constructorArgRT
)
165 CXXRecordDecl
* templateParamRD
= dyn_cast
<CXXRecordDecl
>( templateParamRT
->getDecl() );
166 CXXRecordDecl
* constructorArgRD
= dyn_cast
<CXXRecordDecl
>( constructorArgRT
->getDecl() );
168 if (constructorArgRD
->Equals(templateParamRD
) || constructorArgRD
->isDerivedFrom(templateParamRD
))
169 report( DiagnosticsEngine::Warning
,
170 "the source reference is already a subtype of the destination reference",
171 cce
->getLocStart()) // and the exact position where the message should point
172 << cce
->getSourceRange(); // and the full return statement to highlight (optional)
177 static const Type
* extractTemplateType(Expr
* cce
)
179 QualType cceQT
= cce
->getType();
180 const Type
* cceType
= cceQT
.getTypePtr();
181 const TemplateSpecializationType
* cceTST
= dyn_cast
<TemplateSpecializationType
>( cceType
);
184 if( cceTST
->getNumArgs() != 1 )
186 const TemplateArgument
& cceTA
= cceTST
->getArg(0);
187 QualType templateParamQT
= cceTA
.getAsType();
188 return templateParamQT
.getTypePtr();
191 static Plugin::Registration
< ReferenceCasting
> X( "referencecasting" );
195 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */