Created
March 8, 2015 10:21
-
-
Save vgvassilev/471feedc9de61a9590da to your computer and use it in GitHub Desktop.
Patch provided by Nick Lewycky (see [cfe-dev] CopyPaste detection clang static analyzer)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: include/clang/AST/Expr.h | |
=================================================================== | |
--- include/clang/AST/Expr.h (revision 200870) | |
+++ include/clang/AST/Expr.h (working copy) | |
@@ -690,9 +690,9 @@ | |
} | |
/// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return | |
- /// its subexpression. If that subexpression is also a ParenExpr, | |
- /// then this method recursively returns its subexpression, and so forth. | |
- /// Otherwise, the method returns the current Expr. | |
+ /// its subexpression. If that subexpression is also a ParenExpr, | |
+ /// then this method recursively returns its subexpression, and so forth. | |
+ /// Otherwise, the method returns the current Expr. | |
Expr *IgnoreParens() LLVM_READONLY; | |
/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr | |
Index: include/clang/AST/Stmt.h | |
=================================================================== | |
--- include/clang/AST/Stmt.h (revision 200870) | |
+++ include/clang/AST/Stmt.h (working copy) | |
@@ -431,8 +431,12 @@ | |
/// parameters are identified by index/level rather than their | |
/// declaration pointers) or the exact representation of the statement as | |
/// written in the source. | |
+ /// | |
+ /// \param Macro whether the profile should include the source location of | |
+ /// the site of definition of any macros used in the expansion of this | |
+ /// statement. | |
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, | |
- bool Canonical) const; | |
+ bool Canonical, bool Macro) const; | |
}; | |
/// DeclStmt - Adaptor class for mixing declarations with statements and | |
Index: include/clang/AST/StmtObjC.h | |
=================================================================== | |
--- include/clang/AST/StmtObjC.h (revision 200870) | |
+++ include/clang/AST/StmtObjC.h (working copy) | |
@@ -324,7 +324,7 @@ | |
Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); } | |
void setThrowExpr(Stmt *S) { Throw = S; } | |
- SourceLocation getThrowLoc() { return AtThrowLoc; } | |
+ SourceLocation getThrowLoc() const LLVM_READONLY { return AtThrowLoc; } | |
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } | |
SourceLocation getLocStart() const LLVM_READONLY { return AtThrowLoc; } | |
Index: include/clang/Basic/DiagnosticSemaKinds.td | |
=================================================================== | |
--- include/clang/Basic/DiagnosticSemaKinds.td (revision 200870) | |
+++ include/clang/Basic/DiagnosticSemaKinds.td (working copy) | |
@@ -199,16 +199,16 @@ | |
def warn_unused_private_field: Warning<"private field %0 is not used">, | |
InGroup<UnusedPrivateField>, DefaultIgnore; | |
-def warn_parameter_size: Warning< | |
+def warn_parameter_size : Warning< | |
"%0 is a large (%1 bytes) pass-by-value argument; " | |
"pass it by reference instead ?">, InGroup<LargeByValueCopy>; | |
-def warn_return_value_size: Warning< | |
+def warn_return_value_size : Warning< | |
"return value of %0 is a large (%1 bytes) pass-by-value object; " | |
"pass it by reference instead ?">, InGroup<LargeByValueCopy>; | |
-def warn_return_value_udt: Warning< | |
+def warn_return_value_udt : Warning< | |
"%0 has C-linkage specified, but returns user-defined type %1 which is " | |
"incompatible with C">, InGroup<ReturnTypeCLinkage>; | |
-def warn_return_value_udt_incomplete: Warning< | |
+def warn_return_value_udt_incomplete : Warning< | |
"%0 has C-linkage specified, but returns incomplete type %1 which could be " | |
"incompatible with C">, InGroup<ReturnTypeCLinkage>; | |
def warn_implicit_function_decl : Warning< | |
@@ -6850,4 +6850,10 @@ | |
"not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore; | |
} // end of documentation issue category | |
+def warn_condition_same_stmt : Warning< | |
+ "same %select{statements|expressions}0 on either side of condition">, | |
+ InGroup<DiagGroup<"useless-condition">>; | |
+def note_code_here : Note< | |
+ "in %select{statement|expression}0 here">; | |
+ | |
} // end of sema component. | |
Index: include/clang/Sema/Sema.h | |
=================================================================== | |
--- include/clang/Sema/Sema.h (revision 200870) | |
+++ include/clang/Sema/Sema.h (working copy) | |
@@ -3078,6 +3078,8 @@ | |
void DiagnoseEmptyLoopBody(const Stmt *S, | |
const Stmt *PossibleBody); | |
+ void CheckStatementsUnique(SourceLocation Loc, ArrayRef<Stmt*> Stmts); | |
+ | |
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { | |
return DelayedDiagnostics.push(pool); | |
} | |
Index: lib/AST/StmtProfile.cpp | |
=================================================================== | |
--- lib/AST/StmtProfile.cpp (revision 200870) | |
+++ lib/AST/StmtProfile.cpp (working copy) | |
@@ -27,11 +27,14 @@ | |
llvm::FoldingSetNodeID &ID; | |
const ASTContext &Context; | |
bool Canonical; | |
+ bool Macro; | |
+ void VisitSourceLocation(SourceLocation Loc); | |
+ | |
public: | |
StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context, | |
- bool Canonical) | |
- : ID(ID), Context(Context), Canonical(Canonical) { } | |
+ bool Canonical, bool Macro) | |
+ : ID(ID), Context(Context), Canonical(Canonical), Macro(Macro) { } | |
void VisitStmt(const Stmt *S); | |
@@ -64,9 +67,22 @@ | |
/// \brief Visit a single template argument. | |
void VisitTemplateArgument(const TemplateArgument &Arg); | |
- }; | |
+ }; | |
} | |
+void StmtProfiler::VisitSourceLocation(SourceLocation Loc) { | |
+ if (!Macro) return; | |
+ | |
+ if (Loc.isInvalid() || !Loc.isMacroID()) { | |
+ ID.AddInteger(0); | |
+ return; | |
+ } | |
+ | |
+ SourceLocation MacroDefLoc = | |
+ Context.getSourceManager().getImmediateSpellingLoc(Loc); | |
+ ID.AddInteger(MacroDefLoc.getRawEncoding()); | |
+} | |
+ | |
void StmtProfiler::VisitStmt(const Stmt *S) { | |
ID.AddInteger(S->getStmtClass()); | |
for (Stmt::const_child_range C = S->children(); C; ++C) { | |
@@ -79,6 +95,8 @@ | |
void StmtProfiler::VisitDeclStmt(const DeclStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getStartLoc()); | |
+ VisitSourceLocation(S->getEndLoc()); | |
for (DeclStmt::const_decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); | |
D != DEnd; ++D) | |
VisitDecl(*D); | |
@@ -86,10 +104,13 @@ | |
void StmtProfiler::VisitNullStmt(const NullStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getSemiLoc()); | |
} | |
void StmtProfiler::VisitCompoundStmt(const CompoundStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getLBracLoc()); | |
+ VisitSourceLocation(S->getRBracLoc()); | |
} | |
void StmtProfiler::VisitSwitchCase(const SwitchCase *S) { | |
@@ -98,68 +119,94 @@ | |
void StmtProfiler::VisitCaseStmt(const CaseStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getCaseLoc()); | |
+ VisitSourceLocation(S->getEllipsisLoc()); | |
+ VisitSourceLocation(S->getColonLoc()); | |
} | |
void StmtProfiler::VisitDefaultStmt(const DefaultStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getDefaultLoc()); | |
+ VisitSourceLocation(S->getColonLoc()); | |
} | |
void StmtProfiler::VisitLabelStmt(const LabelStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getIdentLoc()); | |
VisitDecl(S->getDecl()); | |
} | |
void StmtProfiler::VisitAttributedStmt(const AttributedStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAttrLoc()); | |
// TODO: maybe visit attributes? | |
} | |
void StmtProfiler::VisitIfStmt(const IfStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getIfLoc()); | |
+ VisitSourceLocation(S->getElseLoc()); | |
VisitDecl(S->getConditionVariable()); | |
} | |
void StmtProfiler::VisitSwitchStmt(const SwitchStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getSwitchLoc()); | |
VisitDecl(S->getConditionVariable()); | |
} | |
void StmtProfiler::VisitWhileStmt(const WhileStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getWhileLoc()); | |
VisitDecl(S->getConditionVariable()); | |
} | |
void StmtProfiler::VisitDoStmt(const DoStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getDoLoc()); | |
+ VisitSourceLocation(S->getWhileLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitForStmt(const ForStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getForLoc()); | |
+ VisitSourceLocation(S->getLParenLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitGotoStmt(const GotoStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getGotoLoc()); | |
+ VisitSourceLocation(S->getLabelLoc()); | |
VisitDecl(S->getLabel()); | |
} | |
void StmtProfiler::VisitIndirectGotoStmt(const IndirectGotoStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getGotoLoc()); | |
+ VisitSourceLocation(S->getStarLoc()); | |
} | |
void StmtProfiler::VisitContinueStmt(const ContinueStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getContinueLoc()); | |
} | |
void StmtProfiler::VisitBreakStmt(const BreakStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getBreakLoc()); | |
} | |
void StmtProfiler::VisitReturnStmt(const ReturnStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getReturnLoc()); | |
} | |
void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAsmLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
ID.AddBoolean(S->isVolatile()); | |
ID.AddBoolean(S->isSimple()); | |
VisitStringLiteral(S->getAsmString()); | |
@@ -181,23 +228,30 @@ | |
void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) { | |
// FIXME: Implement MS style inline asm statement profiler. | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAsmLoc()); | |
} | |
void StmtProfiler::VisitCXXCatchStmt(const CXXCatchStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getCatchLoc()); | |
VisitType(S->getCaughtType()); | |
} | |
void StmtProfiler::VisitCXXTryStmt(const CXXTryStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getTryLoc()); | |
} | |
void StmtProfiler::VisitCXXForRangeStmt(const CXXForRangeStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getForLoc()); | |
+ VisitSourceLocation(S->getColonLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getKeywordLoc()); | |
ID.AddBoolean(S->isIfExists()); | |
VisitNestedNameSpecifier(S->getQualifierLoc().getNestedNameSpecifier()); | |
VisitName(S->getNameInfo().getName()); | |
@@ -205,14 +259,17 @@ | |
void StmtProfiler::VisitSEHTryStmt(const SEHTryStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getTryLoc()); | |
} | |
void StmtProfiler::VisitSEHFinallyStmt(const SEHFinallyStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getFinallyLoc()); | |
} | |
void StmtProfiler::VisitSEHExceptStmt(const SEHExceptStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getExceptLoc()); | |
} | |
void StmtProfiler::VisitCapturedStmt(const CapturedStmt *S) { | |
@@ -221,10 +278,14 @@ | |
void StmtProfiler::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getForLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAtCatchLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
ID.AddBoolean(S->hasEllipsis()); | |
if (S->getCatchParamDecl()) | |
VisitType(S->getCatchParamDecl()->getType()); | |
@@ -232,24 +293,29 @@ | |
void StmtProfiler::VisitObjCAtFinallyStmt(const ObjCAtFinallyStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAtFinallyLoc()); | |
} | |
void StmtProfiler::VisitObjCAtTryStmt(const ObjCAtTryStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAtTryLoc()); | |
} | |
void | |
StmtProfiler::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAtSynchronizedLoc()); | |
} | |
void StmtProfiler::VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getThrowLoc()); | |
} | |
void | |
StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) { | |
VisitStmt(S); | |
+ VisitSourceLocation(S->getAtLoc()); | |
} | |
namespace { | |
@@ -304,6 +370,7 @@ | |
void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
if (!Canonical) | |
VisitNestedNameSpecifier(S->getQualifier()); | |
VisitDecl(S->getDecl()); | |
@@ -313,16 +380,19 @@ | |
void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
ID.AddInteger(S->getIdentType()); | |
} | |
void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
S->getValue().Profile(ID); | |
} | |
void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
ID.AddInteger(S->getKind()); | |
ID.AddInteger(S->getValue()); | |
} | |
@@ -329,6 +399,7 @@ | |
void StmtProfiler::VisitFloatingLiteral(const FloatingLiteral *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
S->getValue().Profile(ID); | |
ID.AddBoolean(S->isExact()); | |
} | |
@@ -339,6 +410,9 @@ | |
void StmtProfiler::VisitStringLiteral(const StringLiteral *S) { | |
VisitExpr(S); | |
+ for (StringLiteral::tokloc_iterator I = S->tokloc_begin(), | |
+ E = S->tokloc_end(); I != E; ++I) | |
+ VisitSourceLocation(*I); | |
ID.AddString(S->getBytes()); | |
ID.AddInteger(S->getKind()); | |
} | |
@@ -345,22 +419,31 @@ | |
void StmtProfiler::VisitParenExpr(const ParenExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLParen()); | |
+ VisitSourceLocation(S->getRParen()); | |
} | |
void StmtProfiler::VisitParenListExpr(const ParenListExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLParenLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitUnaryOperator(const UnaryOperator *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
ID.AddInteger(S->getOpcode()); | |
} | |
void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) { | |
VisitType(S->getTypeSourceInfo()->getType()); | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
unsigned n = S->getNumComponents(); | |
for (unsigned i = 0; i < n; ++i) { | |
- const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i); | |
+ const OffsetOfExpr::OffsetOfNode &ON = S->getComponent(i); | |
+ VisitSourceLocation(ON.getSourceRange().getBegin()); | |
+ VisitSourceLocation(ON.getSourceRange().getEnd()); | |
ID.AddInteger(ON.getKind()); | |
switch (ON.getKind()) { | |
case OffsetOfExpr::OffsetOfNode::Array: | |
@@ -387,6 +470,8 @@ | |
void | |
StmtProfiler::VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
ID.AddInteger(S->getKind()); | |
if (S->isArgumentType()) | |
VisitType(S->getArgumentType()); | |
@@ -394,14 +479,17 @@ | |
void StmtProfiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getRBracketLoc()); | |
} | |
void StmtProfiler::VisitCallExpr(const CallExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitMemberExpr(const MemberExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getMemberLoc()); | |
VisitDecl(S->getMemberDecl()); | |
if (!Canonical) | |
VisitNestedNameSpecifier(S->getQualifier()); | |
@@ -410,6 +498,7 @@ | |
void StmtProfiler::VisitCompoundLiteralExpr(const CompoundLiteralExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLParenLoc()); | |
ID.AddBoolean(S->isFileScope()); | |
} | |
@@ -429,10 +518,13 @@ | |
void StmtProfiler::VisitCStyleCastExpr(const CStyleCastExpr *S) { | |
VisitExplicitCastExpr(S); | |
+ VisitSourceLocation(S->getLParenLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitBinaryOperator(const BinaryOperator *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
ID.AddInteger(S->getOpcode()); | |
} | |
@@ -443,24 +535,34 @@ | |
void StmtProfiler::VisitConditionalOperator(const ConditionalOperator *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getQuestionLoc()); | |
+ VisitSourceLocation(S->getColonLoc()); | |
} | |
void StmtProfiler::VisitBinaryConditionalOperator( | |
const BinaryConditionalOperator *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getQuestionLoc()); | |
+ VisitSourceLocation(S->getColonLoc()); | |
} | |
void StmtProfiler::VisitAddrLabelExpr(const AddrLabelExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getAmpAmpLoc()); | |
+ VisitSourceLocation(S->getLabelLoc()); | |
VisitDecl(S->getLabel()); | |
} | |
void StmtProfiler::VisitStmtExpr(const StmtExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLParenLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getBuiltinLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitConvertVectorExpr(const ConvertVectorExpr *S) { | |
@@ -469,14 +571,19 @@ | |
void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getBuiltinLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitGNUNullExpr(const GNUNullExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getTokenLocation()); | |
} | |
void StmtProfiler::VisitVAArgExpr(const VAArgExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getBuiltinLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitInitListExpr(const InitListExpr *S) { | |
@@ -486,24 +593,32 @@ | |
} | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLBraceLoc()); | |
+ VisitSourceLocation(S->getRBraceLoc()); | |
} | |
void StmtProfiler::VisitDesignatedInitExpr(const DesignatedInitExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getEqualOrColonLoc()); | |
ID.AddBoolean(S->usesGNUSyntax()); | |
for (DesignatedInitExpr::const_designators_iterator D = | |
S->designators_begin(), DEnd = S->designators_end(); | |
D != DEnd; ++D) { | |
if (D->isFieldDesignator()) { | |
+ VisitSourceLocation(D->getDotLoc()); | |
+ VisitSourceLocation(D->getFieldLoc()); | |
ID.AddInteger(0); | |
VisitName(D->getFieldName()); | |
continue; | |
} | |
+ VisitSourceLocation(D->getLBracketLoc()); | |
+ VisitSourceLocation(D->getRBracketLoc()); | |
if (D->isArrayDesignator()) { | |
ID.AddInteger(1); | |
} else { | |
assert(D->isArrayRangeDesignator()); | |
+ VisitSourceLocation(D->getEllipsisLoc()); | |
ID.AddInteger(2); | |
} | |
ID.AddInteger(D->getFirstExprIndex()); | |
@@ -516,6 +631,7 @@ | |
void StmtProfiler::VisitExtVectorElementExpr(const ExtVectorElementExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getAccessorLoc()); | |
VisitName(&S->getAccessor()); | |
} | |
@@ -526,6 +642,9 @@ | |
void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getGenericLoc()); | |
+ VisitSourceLocation(S->getDefaultLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
for (unsigned i = 0; i != S->getNumAssocs(); ++i) { | |
QualType T = S->getAssocType(i); | |
if (T.isNull()) | |
@@ -547,6 +666,8 @@ | |
void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getBuiltinLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
ID.AddInteger(S->getOp()); | |
} | |
@@ -772,10 +893,14 @@ | |
void StmtProfiler::VisitAsTypeExpr(const AsTypeExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getBuiltinLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitCXXNamedCastExpr(const CXXNamedCastExpr *S) { | |
VisitExplicitCastExpr(S); | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { | |
@@ -797,15 +922,18 @@ | |
void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) { | |
VisitCallExpr(S); | |
+ VisitSourceLocation(S->getUDSuffixLoc()); | |
} | |
void StmtProfiler::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
ID.AddBoolean(S->getValue()); | |
} | |
void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
} | |
void StmtProfiler::VisitCXXStdInitializerListExpr( | |
@@ -815,6 +943,8 @@ | |
void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
+ VisitSourceLocation(S->getSourceRange().getEnd()); | |
if (S->isTypeOperand()) | |
VisitType(S->getTypeOperandSourceInfo()->getType()); | |
} | |
@@ -821,6 +951,8 @@ | |
void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
+ VisitSourceLocation(S->getSourceRange().getEnd()); | |
if (S->isTypeOperand()) | |
VisitType(S->getTypeOperandSourceInfo()->getType()); | |
} | |
@@ -832,15 +964,18 @@ | |
void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
ID.AddBoolean(S->isImplicit()); | |
} | |
void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getThrowLoc()); | |
} | |
void StmtProfiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getUsedLocation()); | |
VisitDecl(S->getParam()); | |
} | |
@@ -857,6 +992,9 @@ | |
void StmtProfiler::VisitCXXConstructExpr(const CXXConstructExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
+ VisitSourceLocation(S->getParenOrBraceRange().getBegin()); | |
+ VisitSourceLocation(S->getParenOrBraceRange().getEnd()); | |
VisitDecl(S->getConstructor()); | |
ID.AddBoolean(S->isElidable()); | |
} | |
@@ -863,19 +1001,27 @@ | |
void StmtProfiler::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { | |
VisitExplicitCastExpr(S); | |
+ VisitSourceLocation(S->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void | |
StmtProfiler::VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { | |
VisitCXXConstructExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
+ VisitSourceLocation(S->getSourceRange().getEnd()); | |
} | |
void | |
StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getIntroducerRange().getBegin()); | |
+ VisitSourceLocation(S->getIntroducerRange().getEnd()); | |
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), | |
CEnd = S->explicit_capture_end(); | |
C != CEnd; ++C) { | |
+ VisitSourceLocation(C->getLocation()); | |
+ VisitSourceLocation(C->getEllipsisLoc()); | |
ID.AddInteger(C->getCaptureKind()); | |
switch (C->getCaptureKind()) { | |
case LCK_This: | |
@@ -896,10 +1042,12 @@ | |
void | |
StmtProfiler::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
} | |
void StmtProfiler::VisitCXXDeleteExpr(const CXXDeleteExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
ID.AddBoolean(S->isGlobalDelete()); | |
ID.AddBoolean(S->isArrayForm()); | |
VisitDecl(S->getOperatorDelete()); | |
@@ -908,6 +1056,12 @@ | |
void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getTypeIdParens().getBegin()); | |
+ VisitSourceLocation(S->getTypeIdParens().getEnd()); | |
+ VisitSourceLocation(S->getStartLoc()); | |
+ VisitSourceLocation(S->getEndLoc()); | |
+ VisitSourceLocation(S->getDirectInitRange().getBegin()); | |
+ VisitSourceLocation(S->getDirectInitRange().getEnd()); | |
VisitType(S->getAllocatedType()); | |
VisitDecl(S->getOperatorNew()); | |
VisitDecl(S->getOperatorDelete()); | |
@@ -921,6 +1075,10 @@ | |
void | |
StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
+ VisitSourceLocation(S->getColonColonLoc()); | |
+ VisitSourceLocation(S->getTildeLoc()); | |
+ VisitSourceLocation(S->getDestroyedTypeLoc()); | |
ID.AddBoolean(S->isArrow()); | |
VisitNestedNameSpecifier(S->getQualifier()); | |
ID.AddBoolean(S->getScopeTypeInfo() != 0); | |
@@ -935,6 +1093,7 @@ | |
void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getNameLoc()); | |
VisitNestedNameSpecifier(S->getQualifier()); | |
VisitName(S->getName()); | |
ID.AddBoolean(S->hasExplicitTemplateArgs()); | |
@@ -950,6 +1109,8 @@ | |
void StmtProfiler::VisitTypeTraitExpr(const TypeTraitExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
+ VisitSourceLocation(S->getSourceRange().getEnd()); | |
ID.AddInteger(S->getTrait()); | |
ID.AddInteger(S->getNumArgs()); | |
for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) | |
@@ -958,6 +1119,8 @@ | |
void StmtProfiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
+ VisitSourceLocation(S->getSourceRange().getEnd()); | |
ID.AddInteger(S->getTrait()); | |
VisitType(S->getQueriedType()); | |
} | |
@@ -964,6 +1127,8 @@ | |
void StmtProfiler::VisitExpressionTraitExpr(const ExpressionTraitExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getSourceRange().getBegin()); | |
+ VisitSourceLocation(S->getSourceRange().getEnd()); | |
ID.AddInteger(S->getTrait()); | |
VisitExpr(S->getQueriedExpression()); | |
} | |
@@ -971,6 +1136,7 @@ | |
void StmtProfiler::VisitDependentScopeDeclRefExpr( | |
const DependentScopeDeclRefExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLocation()); | |
VisitName(S->getDeclName()); | |
VisitNestedNameSpecifier(S->getQualifier()); | |
ID.AddBoolean(S->hasExplicitTemplateArgs()); | |
@@ -985,11 +1151,15 @@ | |
void StmtProfiler::VisitCXXUnresolvedConstructExpr( | |
const CXXUnresolvedConstructExpr *S) { | |
VisitExpr(S); | |
+ VisitSourceLocation(S->getLParenLoc()); | |
+ VisitSourceLocation(S->getRParenLoc()); | |
VisitType(S->getTypeAsWritten()); | |
} | |
void StmtProfiler::VisitCXXDependentScopeMemberExpr( | |
const CXXDependentScopeMemberExpr *S) { | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
+ VisitSourceLocation(S->getMemberLoc()); | |
ID.AddBoolean(S->isImplicitAccess()); | |
if (!S->isImplicitAccess()) { | |
VisitExpr(S); | |
@@ -1003,6 +1173,9 @@ | |
} | |
void StmtProfiler::VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *S) { | |
+ VisitSourceLocation(S->getOperatorLoc()); | |
+ VisitSourceLocation(S->getMemberLoc()); | |
+ /// XXX stopped here | |
ID.AddBoolean(S->isImplicitAccess()); | |
if (!S->isImplicitAccess()) { | |
VisitExpr(S); | |
@@ -1056,6 +1229,7 @@ | |
void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { | |
VisitExpr(E); | |
+ VisitSourceLocation(E->getLocation()); | |
} | |
void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) { | |
@@ -1120,6 +1294,9 @@ | |
VisitExpr(S); | |
VisitName(S->getSelector()); | |
VisitDecl(S->getMethodDecl()); | |
+ ID.AddInteger(S->getReceiverKind()); | |
+ if (S->getReceiverKind() == ObjCMessageExpr::Class) | |
+ VisitType(S->getClassReceiver()); | |
} | |
void StmtProfiler::VisitObjCIsaExpr(const ObjCIsaExpr *S) { | |
@@ -1263,7 +1440,7 @@ | |
} | |
void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, | |
- bool Canonical) const { | |
- StmtProfiler Profiler(ID, Context, Canonical); | |
+ bool Canonical, bool Macro) const { | |
+ StmtProfiler Profiler(ID, Context, Canonical, Macro); | |
Profiler.Visit(this); | |
} | |
Index: lib/AST/TemplateBase.cpp | |
=================================================================== | |
--- lib/AST/TemplateBase.cpp (revision 200870) | |
+++ lib/AST/TemplateBase.cpp (working copy) | |
@@ -275,7 +275,7 @@ | |
break; | |
case Expression: | |
- getAsExpr()->Profile(ID, Context, true); | |
+ getAsExpr()->Profile(ID, Context, true, false); | |
break; | |
case Pack: | |
Index: lib/AST/Type.cpp | |
=================================================================== | |
--- lib/AST/Type.cpp (revision 200870) | |
+++ lib/AST/Type.cpp (working copy) | |
@@ -141,7 +141,7 @@ | |
ID.AddPointer(ET.getAsOpaquePtr()); | |
ID.AddInteger(SizeMod); | |
ID.AddInteger(TypeQuals); | |
- E->Profile(ID, Context, true); | |
+ E->Profile(ID, Context, true, false); | |
} | |
DependentSizedExtVectorType::DependentSizedExtVectorType(const | |
@@ -165,7 +165,7 @@ | |
const ASTContext &Context, | |
QualType ElementType, Expr *SizeExpr) { | |
ID.AddPointer(ElementType.getAsOpaquePtr()); | |
- SizeExpr->Profile(ID, Context, true); | |
+ SizeExpr->Profile(ID, Context, true, false); | |
} | |
VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, | |
@@ -1761,7 +1761,7 @@ | |
for (unsigned i = 0; i != epi.NumExceptions; ++i) | |
ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); | |
} else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ | |
- epi.NoexceptExpr->Profile(ID, Context, false); | |
+ epi.NoexceptExpr->Profile(ID, Context, false, false); | |
} else if (epi.ExceptionSpecType == EST_Uninstantiated || | |
epi.ExceptionSpecType == EST_Unevaluated) { | |
ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl()); | |
@@ -1805,7 +1805,7 @@ | |
void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, | |
const ASTContext &Context, Expr *E) { | |
- E->Profile(ID, Context, true); | |
+ E->Profile(ID, Context, true, false); | |
} | |
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) | |
@@ -1834,7 +1834,7 @@ | |
void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, | |
const ASTContext &Context, Expr *E) { | |
- E->Profile(ID, Context, true); | |
+ E->Profile(ID, Context, true, false); | |
} | |
TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) | |
Index: lib/Sema/SemaChecking.cpp | |
=================================================================== | |
--- lib/Sema/SemaChecking.cpp (revision 200870) | |
+++ lib/Sema/SemaChecking.cpp (working copy) | |
@@ -1576,10 +1576,10 @@ | |
TheCall->setArg(i+1, Arg.take()); | |
} | |
- ASTContext& Context = this->getASTContext(); | |
+ ASTContext &Context = this->getASTContext(); | |
// Create a new DeclRefExpr to refer to the new decl. | |
- DeclRefExpr* NewDRE = DeclRefExpr::Create( | |
+ DeclRefExpr *NewDRE = DeclRefExpr::Create( | |
Context, | |
DRE->getQualifierLoc(), | |
SourceLocation(), | |
@@ -3632,7 +3632,7 @@ | |
/// \brief If E is a sizeof expression, returns its argument expression, | |
/// otherwise returns NULL. | |
-static const Expr *getSizeOfExprArg(const Expr* E) { | |
+static const Expr *getSizeOfExprArg(const Expr *E) { | |
if (const UnaryExprOrTypeTraitExpr *SizeOf = | |
dyn_cast<UnaryExprOrTypeTraitExpr>(E)) | |
if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType()) | |
@@ -3706,9 +3706,9 @@ | |
// We only compute IDs for expressions if the warning is enabled, and | |
// cache the sizeof arg's ID. | |
if (SizeOfArgID == llvm::FoldingSetNodeID()) | |
- SizeOfArg->Profile(SizeOfArgID, Context, true); | |
+ SizeOfArg->Profile(SizeOfArgID, Context, true, false); | |
llvm::FoldingSetNodeID DestID; | |
- Dest->Profile(DestID, Context, true); | |
+ Dest->Profile(DestID, Context, true, false); | |
if (DestID == SizeOfArgID) { | |
// TODO: For strncpy() and friends, this could suggest sizeof(dst) | |
// over sizeof(src) as well. | |
@@ -3818,7 +3818,7 @@ | |
Ex = Ex->IgnoreParenCasts(); | |
for (;;) { | |
- const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex); | |
+ const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex); | |
if (!BO || !BO->isAdditiveOp()) | |
break; | |
@@ -5630,6 +5630,18 @@ | |
SourceLocation CC, QualType T) { | |
AnalyzeImplicitConversions(S, E->getCond(), CC); | |
+ if (S.ActiveTemplateInstantiations.empty()) { | |
+ SmallVector<Stmt*, 2> Exprs; | |
+ Exprs.push_back(E->getTrueExpr()); | |
+ ConditionalOperator *CO = | |
+ dyn_cast<ConditionalOperator>(E->getFalseExpr()); | |
+ if (CO && !CO->getCond()->HasSideEffects(S.getASTContext())) | |
+ Exprs.push_back(CO->getTrueExpr()); | |
+ else | |
+ Exprs.push_back(E->getFalseExpr()); | |
+ S.CheckStatementsUnique(E->getColonLoc(), Exprs); | |
+ } | |
+ | |
bool Suspicious = false; | |
CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); | |
CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); | |
@@ -7356,6 +7368,7 @@ | |
} | |
} | |
} | |
+} // unnamed namespace | |
/// \brief Retrieve the C type corresponding to type tag TypeExpr. | |
/// | |
@@ -7369,7 +7382,7 @@ | |
/// \param TypeInfo Information about the corresponding C type. | |
/// | |
/// \returns true if the corresponding C type was found. | |
-bool GetMatchingCType( | |
+static bool GetMatchingCType( | |
const IdentifierInfo *ArgumentKind, | |
const Expr *TypeExpr, const ASTContext &Ctx, | |
const llvm::DenseMap<Sema::TypeTagMagicValue, | |
@@ -7415,7 +7428,6 @@ | |
TypeInfo = I->second; | |
return true; | |
} | |
-} // unnamed namespace | |
void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, | |
uint64_t MagicValue, QualType Type, | |
@@ -7430,8 +7442,7 @@ | |
TypeTagData(Type, LayoutCompatible, MustBeNull); | |
} | |
-namespace { | |
-bool IsSameCharType(QualType T1, QualType T2) { | |
+static bool IsSameCharType(QualType T1, QualType T2) { | |
const BuiltinType *BT1 = T1->getAs<BuiltinType>(); | |
if (!BT1) | |
return false; | |
@@ -7448,7 +7459,6 @@ | |
(T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || | |
(T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); | |
} | |
-} // unnamed namespace | |
void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, | |
const Expr * const *ExprArgs) { | |
@@ -7528,3 +7538,64 @@ | |
<< ArgumentExpr->getSourceRange() | |
<< TypeTagExpr->getSourceRange(); | |
} | |
+ | |
+static SourceLocation GetFirstLineLoc(Stmt *S) { | |
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { | |
+ CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); | |
+ while (I != E && *I == NULL) | |
+ ++I; | |
+ if (I == E) | |
+ // A compound statement with no non-NULL statements inside it. Could | |
+ // be { }. Point to the leading '{'. | |
+ return CS->getLocStart(); | |
+ return GetFirstLineLoc(*I); | |
+ } | |
+ | |
+ return S->getLocStart(); | |
+} | |
+ | |
+/// Verify that all of the statements in the list are unique. The statements | |
+/// should be given in source order in order to provide diagnostics the right | |
+/// way around. | |
+void Sema::CheckStatementsUnique(SourceLocation Loc, ArrayRef<Stmt*> Stmts) { | |
+ llvm::DenseMap<unsigned, unsigned> Profiles; | |
+ for (int i = 0, e = Stmts.size(); i != e; ++i) { | |
+ llvm::FoldingSetNodeID ProfileID; | |
+ Stmts[i]->Profile(ProfileID, Context, true, true); | |
+ unsigned ProfileHash = ProfileID.ComputeHash(); | |
+ if (!Profiles.insert(std::make_pair(ProfileHash, i)).second) { | |
+ unsigned j = Profiles[ProfileHash]; | |
+ SourceManager &SM = PP.getSourceManager(); | |
+ FullSourceLoc First = FullSourceLoc(GetFirstLineLoc(Stmts[j]), SM); | |
+ FullSourceLoc Second = FullSourceLoc(GetFirstLineLoc(Stmts[i]), SM); | |
+ FullSourceLoc FullLoc = FullSourceLoc(Loc, SM); | |
+ bool FirstSameLine = First.getFileID() == FullLoc.getFileID() && | |
+ First.getSpellingLineNumber() == FullLoc.getSpellingLineNumber(); | |
+ bool SecondSameLine = Second.getFileID() == FullLoc.getFileID() && | |
+ Second.getSpellingLineNumber() == FullLoc.getSpellingLineNumber(); | |
+ | |
+ if (FirstSameLine && SecondSameLine) { | |
+ Diag(Loc, diag::warn_condition_same_stmt) | |
+ << (isa<Expr>(Stmts[i]) && isa<Expr>(Stmts[j])) | |
+ << Stmts[j]->getSourceRange() | |
+ << Stmts[i]->getSourceRange(); | |
+ } else if (FirstSameLine) { | |
+ Diag(Loc, diag::warn_condition_same_stmt) | |
+ << (isa<Expr>(Stmts[i]) && isa<Expr>(Stmts[j])) | |
+ << Stmts[j]->getSourceRange(); | |
+ Diag(Second, diag::note_code_here) << (isa<Expr>(Stmts[i])); | |
+ } else if (SecondSameLine) { | |
+ Diag(Loc, diag::warn_condition_same_stmt) | |
+ << (isa<Expr>(Stmts[i]) && isa<Expr>(Stmts[j])) | |
+ << Stmts[i]->getSourceRange(); | |
+ Diag(First, diag::note_code_here) << (isa<Expr>(Stmts[j])); | |
+ } else { | |
+ Diag(Loc, diag::warn_condition_same_stmt) | |
+ << (isa<Expr>(Stmts[i]) && isa<Expr>(Stmts[j])); | |
+ Diag(First, diag::note_code_here) << (isa<Expr>(Stmts[j])); | |
+ Diag(Second, diag::note_code_here) << (isa<Expr>(Stmts[i])); | |
+ } | |
+ } | |
+ } | |
+} | |
+ | |
Index: lib/Sema/SemaOverload.cpp | |
=================================================================== | |
--- lib/Sema/SemaOverload.cpp (revision 200870) | |
+++ lib/Sema/SemaOverload.cpp (working copy) | |
@@ -1086,8 +1086,8 @@ | |
if (NewI == NewE || OldI == OldE) | |
return true; | |
llvm::FoldingSetNodeID NewID, OldID; | |
- NewI->getCond()->Profile(NewID, Context, true); | |
- OldI->getCond()->Profile(OldID, Context, true); | |
+ NewI->getCond()->Profile(NewID, Context, true, false); | |
+ OldI->getCond()->Profile(OldID, Context, true, false); | |
if (NewID != OldID) | |
return true; | |
} | |
@@ -8276,9 +8276,11 @@ | |
return true; | |
llvm::FoldingSetNodeID Cand1ID, Cand2ID; | |
cast<EnableIfAttr>(*Cand1I)->getCond()->Profile(Cand1ID, | |
- S.getASTContext(), true); | |
+ S.getASTContext(), | |
+ true, false); | |
cast<EnableIfAttr>(*Cand2I)->getCond()->Profile(Cand2ID, | |
- S.getASTContext(), true); | |
+ S.getASTContext(), | |
+ true, false); | |
if (Cand1ID != Cand2ID) | |
return false; | |
} | |
Index: lib/Sema/SemaStmt.cpp | |
=================================================================== | |
--- lib/Sema/SemaStmt.cpp (revision 200870) | |
+++ lib/Sema/SemaStmt.cpp (working copy) | |
@@ -458,6 +458,17 @@ | |
DiagnoseUnusedExprResult(elseStmt); | |
+ if (ActiveTemplateInstantiations.empty() && elseStmt) { | |
+ SmallVector<Stmt*, 2> Exprs; | |
+ Exprs.push_back(thenStmt); | |
+ IfStmt *elseIfStmt = dyn_cast<IfStmt>(elseStmt); | |
+ if (elseIfStmt && !elseIfStmt->getCond()->HasSideEffects(Context)) | |
+ Exprs.push_back(elseIfStmt->getThen()); | |
+ else | |
+ Exprs.push_back(elseStmt); | |
+ CheckStatementsUnique(ElseLoc, Exprs); | |
+ } | |
+ | |
return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, | |
thenStmt, ElseLoc, elseStmt)); | |
} | |
Index: lib/Sema/SemaTemplateDeduction.cpp | |
=================================================================== | |
--- lib/Sema/SemaTemplateDeduction.cpp (revision 200870) | |
+++ lib/Sema/SemaTemplateDeduction.cpp (working copy) | |
@@ -239,8 +239,8 @@ | |
if (Y.getKind() == TemplateArgument::Expression) { | |
// Compare the expressions for equality | |
llvm::FoldingSetNodeID ID1, ID2; | |
- X.getAsExpr()->Profile(ID1, Context, true); | |
- Y.getAsExpr()->Profile(ID2, Context, true); | |
+ X.getAsExpr()->Profile(ID1, Context, true, false); | |
+ Y.getAsExpr()->Profile(ID2, Context, true, false); | |
if (ID1 == ID2) | |
return X; | |
} | |
@@ -1970,8 +1970,8 @@ | |
case TemplateArgument::Expression: { | |
llvm::FoldingSetNodeID XID, YID; | |
- X.getAsExpr()->Profile(XID, Context, true); | |
- Y.getAsExpr()->Profile(YID, Context, true); | |
+ X.getAsExpr()->Profile(XID, Context, true, false); | |
+ Y.getAsExpr()->Profile(YID, Context, true, false); | |
return XID == YID; | |
} | |
Index: test/Analysis/additive-folding-range-constraints.c | |
=================================================================== | |
--- test/Analysis/additive-folding-range-constraints.c (revision 200870) | |
+++ test/Analysis/additive-folding-range-constraints.c (working copy) | |
@@ -117,11 +117,11 @@ | |
clang_analyzer_eval((a + 5) == 0LL); // expected-warning{{UNKNOWN}} | |
if ((a + 5) == 0LL) { | |
- clang_analyzer_eval(a == 0); // expected-warning{{FALSE}} | |
+ clang_analyzer_eval(a == 0); // expected-warning{{FALSE}} // expected-note{{in statement here}} | |
clang_analyzer_eval(a == 0x7F); // expected-warning{{FALSE}} | |
clang_analyzer_eval(a == -0x80); // expected-warning{{FALSE}} | |
- } else { | |
- clang_analyzer_eval(a == 0); // expected-warning{{UNKNOWN}} | |
+ } else { // expected-warning{{same statements on either side of condition}} | |
+ clang_analyzer_eval(a == 0); // expected-warning{{UNKNOWN}} // expected-note{{in statement here}} | |
clang_analyzer_eval(a == 0x7F); // expected-warning{{UNKNOWN}} | |
clang_analyzer_eval(a == -0x80); // expected-warning{{UNKNOWN}} | |
} | |
Index: test/Analysis/identical-expressions.cpp | |
=================================================================== | |
--- test/Analysis/identical-expressions.cpp (revision 200870) | |
+++ test/Analysis/identical-expressions.cpp (working copy) | |
@@ -1,4 +1,4 @@ | |
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.IdenticalExpr -verify %s | |
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.IdenticalExpr -verify -Wno-useless-condition %s | |
/* Only one expected warning per function allowed at the very end. */ | |
Index: test/Analysis/inlining/test-always-inline-size-option.c | |
=================================================================== | |
--- test/Analysis/inlining/test-always-inline-size-option.c (revision 200870) | |
+++ test/Analysis/inlining/test-always-inline-size-option.c (working copy) | |
@@ -4,9 +4,10 @@ | |
int nested5() { | |
if (5 < 3) | |
return 0; | |
- else | |
+ else { | |
if (3 == 3) | |
return 0; | |
+ } | |
return 0; | |
} | |
int nested4() { | |
Index: test/Analysis/malloc-interprocedural.c | |
=================================================================== | |
--- test/Analysis/malloc-interprocedural.c (revision 200870) | |
+++ test/Analysis/malloc-interprocedural.c (working copy) | |
@@ -121,15 +121,15 @@ | |
return result; | |
} | |
-void useStrndup(size_t n) { | |
+int useStrndup(size_t n) { | |
if (n == 0) { | |
(void)strndup(0, 20); // no-warning | |
- return; | |
+ return 0; | |
} else if (n < 5) { | |
(void)strndup("hi there", n); // no-warning | |
- return; | |
+ return 1; | |
} else { | |
(void)strndup("hi there", n); | |
- return; // expected-warning{{leak}} | |
+ return 2; // expected-warning{{leak}} | |
} | |
} | |
Index: test/Analysis/malloc.c | |
=================================================================== | |
--- test/Analysis/malloc.c (revision 200870) | |
+++ test/Analysis/malloc.c (working copy) | |
@@ -416,9 +416,9 @@ | |
void mallocFailedOrNot() { | |
int *p = malloc(12); | |
if (!p) | |
- free(p); | |
- else | |
- free(p); | |
+ free(p); // expected-note{{in expression here}} | |
+ else // expected-warning{{same expressions on either side of condition}} | |
+ free(p); // expected-note{{in expression here}} | |
} | |
struct StructWithInt { | |
@@ -446,12 +446,12 @@ | |
return; // no warning | |
} | |
-void mallocFailedOrNotLeak() { | |
+int mallocFailedOrNotLeak() { | |
int *p = malloc(12); | |
if (p == 0) | |
- return; // no warning | |
+ return 0; // no warning | |
else | |
- return; // expected-warning {{Potential leak of memory pointed to by}} | |
+ return 1; // expected-warning {{Potential leak of memory pointed to by}} | |
} | |
void mallocAssignment() { | |
@@ -813,7 +813,7 @@ | |
free(buffer); | |
} | |
-void radar10978247_positive(int myValueSize) { | |
+int radar10978247_positive(int myValueSize) { | |
char stackBuffer[128]; | |
char *buffer; | |
@@ -824,10 +824,11 @@ | |
// do stuff with the buffer | |
if (buffer == stackBuffer) | |
- return; | |
+ return 0; | |
else | |
- return; // expected-warning {{leak}} | |
-} | |
+ return 1; // expected-warning {{leak}} | |
+} | |
+ | |
// <rdar://problem/11269741> Previously this triggered a false positive | |
// because malloc() is known to return uninitialized memory and the binding | |
// of 'o' to 'p->n' was not getting propertly handled. Now we report a leak. | |
Index: test/Analysis/misc-ps-region-store.cpp | |
=================================================================== | |
--- test/Analysis/misc-ps-region-store.cpp (revision 200870) | |
+++ test/Analysis/misc-ps-region-store.cpp (working copy) | |
@@ -584,13 +584,15 @@ | |
} | |
// Test handling CXXScalarValueInitExprs. | |
-void rdar11401827() { | |
+int rdar11401827() { | |
int x = int(); | |
if (!x) { | |
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | |
+ return 0; | |
} | |
else { | |
clang_analyzer_warnIfReached(); // no-warning | |
+ return 1; | |
} | |
} | |
Index: test/Analysis/operator-calls.cpp | |
=================================================================== | |
--- test/Analysis/operator-calls.cpp (revision 200870) | |
+++ test/Analysis/operator-calls.cpp (working copy) | |
@@ -1,4 +1,4 @@ | |
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s | |
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -Wno-useless-condition %s | |
void clang_analyzer_eval(bool); | |
struct X0 { }; | |
Index: test/Analysis/retain-release.m | |
=================================================================== | |
--- test/Analysis/retain-release.m (revision 200870) | |
+++ test/Analysis/retain-release.m (working copy) | |
@@ -1893,9 +1893,9 @@ | |
@autoreleasepool { | |
NSString *printString; | |
if(y > 2) | |
- printString = [[NSString alloc] init]; | |
- else | |
- printString = [[NSString alloc] init]; | |
+ printString = [[NSString alloc] init]; // expected-note {{in expression here}} | |
+ else // expected-warning {{same expressions on either side of condition}} | |
+ printString = [[NSString alloc] init]; // expected-note {{in expression here}} | |
NSLog(@"Once %@", printString); | |
[printString release]; | |
NSLog(@"Again: %@", printString); // expected-warning {{Reference-counted object is used after it is released}} | |
Index: test/Analysis/weak-functions.c | |
=================================================================== | |
--- test/Analysis/weak-functions.c (revision 200870) | |
+++ test/Analysis/weak-functions.c (working copy) | |
@@ -4,35 +4,41 @@ | |
void myFunc(); | |
void myWeakFunc() __attribute__((weak_import)); | |
-void testWeakFuncIsNull() | |
+int testWeakFuncIsNull() | |
{ | |
clang_analyzer_eval(myFunc == NULL); // expected-warning{{FALSE}} | |
clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} | |
if (myWeakFunc == NULL) { | |
clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} | |
+ return 0; | |
} else { | |
clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} | |
+ return 1; | |
} | |
} | |
-void testWeakFuncIsNot() | |
+int testWeakFuncIsNot() | |
{ | |
clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} | |
if (!myWeakFunc) { | |
clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} | |
+ return 0; | |
} else { | |
clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} | |
+ return 1; | |
} | |
} | |
-void testWeakFuncIsTrue() | |
+int testWeakFuncIsTrue() | |
{ | |
- clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} | |
- if (myWeakFunc) { | |
- clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} | |
- } else { | |
- clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} | |
- } | |
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} | |
+ if (myWeakFunc) { | |
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} | |
+ return 0; | |
+ } else { | |
+ clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} | |
+ return 1; | |
+ } | |
} | |
//===----------------------------------------------------------------------=== | |
Index: test/SemaCXX/warn-useless-condition.cpp | |
=================================================================== | |
--- test/SemaCXX/warn-useless-condition.cpp (revision 0) | |
+++ test/SemaCXX/warn-useless-condition.cpp (working copy) | |
@@ -0,0 +1,112 @@ | |
+// RUN: %clang_cc1 -Wuseless-condition -verify %s | |
+ | |
+extern int code(); | |
+ | |
+void test1(int expr) { | |
+ if (expr) { | |
+ code(); // expected-note{{in statement here}} | |
+ } else { // expected-warning{{same statements on either side of condition}} | |
+ code(); // expected-note{{in statement here}} | |
+ } | |
+} | |
+ | |
+int test2(int expr) { | |
+ return expr ? code() : code(); // expected-warning{{same expressions on either side of condition}} | |
+} | |
+ | |
+void test3(int expr, int expr2) { | |
+ // We don't want to warn on this. expr2 may be long and complicated and we | |
+ // shouldn't force people to repeat " && !expr2" in each condition leading | |
+ // up to that block. | |
+ if (expr) { | |
+ code(); | |
+ } else if (expr2) { | |
+ return; | |
+ } else { | |
+ code(); | |
+ } | |
+} | |
+ | |
+int test4(int expr, int expr2) { | |
+ // It's conservative, but we don't want to warn on this either. Treating if | |
+ // and ?: differently is too close to being a style issue. | |
+ return expr ? (expr2 ? code() : 0) : code(); | |
+} | |
+ | |
+void test5(int expr) { | |
+ if (expr) { | |
+ code(); | |
+ } else if (code()) { | |
+ code(); // expected-note{{in statement here}} | |
+ } else { // expected-warning{{same statements on either side of condition}} | |
+ code(); // expected-note{{in statement here}} | |
+ } | |
+} | |
+ | |
+int test6(int x, int y, int z) { | |
+ if (x) { | |
+ return 0; | |
+ } else if (y) { | |
+ return 1; | |
+ } else if (z) { | |
+ return 0; | |
+ } else { | |
+ return 1; | |
+ } | |
+} | |
+ | |
+struct true_type { | |
+ static const bool value = true; | |
+ operator bool() { return value; } | |
+}; | |
+struct false_type { | |
+ static const bool value = false; | |
+ operator bool() { return value; } | |
+}; | |
+template <typename T> struct is_pointer : false_type {}; | |
+template <typename T> struct is_pointer<T*> : true_type {}; | |
+template <typename T, typename U> struct is_same : public false_type {}; | |
+template <typename T> struct is_same<T, T> : public true_type {}; | |
+ | |
+template <typename T> | |
+int test7_util(int expr) { | |
+ if (expr) | |
+ return is_pointer<T>::value; | |
+ else | |
+ return is_same<T, T>::value; | |
+} | |
+ | |
+int test7(int expr) { | |
+ return test7_util<int*>(expr); | |
+} | |
+ | |
+#define num_cpus() (1) | |
+#define max_omp_threads() (1) | |
+ | |
+int test8(int expr) { | |
+ if (expr) { | |
+ return num_cpus(); | |
+ } else { | |
+ return max_omp_threads(); | |
+ } | |
+} | |
+ | |
+int test9(int expr) { | |
+ if (expr) { | |
+ return num_cpus(); // expected-note{{in statement here}} | |
+ } else { // expected-warning{{same statements on either side of condition}} | |
+ return num_cpus(); // expected-note{{in statement here}} | |
+ } | |
+} | |
+ | |
+/* This is a false positive. | |
+#define BLANK | |
+ | |
+int test10(int x, int expr) { | |
+ if (expr) { | |
+ return x > -5; | |
+ } else { | |
+ return x > BLANK - 5; | |
+ } | |
+} | |
+*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment