Patch by Chris Wailes <chris.wailes@gmail.com>.
Reviewed by delesley, dblaikie.

Add the annotations and code needed to support a basic 'consumed' analysis.

Summary:
This new analysis is based on academic literature on linear types.  It tracks
the state of a value, either as unconsumed, consumed, or unknown.  Methods are
then annotated as CallableWhenUnconsumed, and when an annotated method is
called while the value is in the 'consumed' state a warning is issued.  A value
may be tested in the conditional statement of an if-statement; when this occurs
we know the state of the value in the different branches, and this information
is added to our analysis.  The code is still highly experimental, and the names
of annotations or the algorithm may be subject to change.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188206 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index af404a5..19fc29b 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -25,6 +25,7 @@
 #include "clang/AST/StmtObjC.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/Consumed.h"
 #include "clang/Analysis/Analyses/ReachableCode.h"
 #include "clang/Analysis/Analyses/ThreadSafety.h"
 #include "clang/Analysis/Analyses/UninitializedValues.h"
@@ -1241,12 +1242,8 @@
 };
 }
 
-
-//===----------------------------------------------------------------------===//
-// -Wthread-safety
-//===----------------------------------------------------------------------===//
 namespace clang {
-namespace thread_safety {
+namespace {
 typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
 typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
 typedef std::list<DelayedDiag> DiagList;
@@ -1261,7 +1258,13 @@
     return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
   }
 };
+}}
 
+//===----------------------------------------------------------------------===//
+// -Wthread-safety
+//===----------------------------------------------------------------------===//
+namespace clang {
+namespace thread_safety {
 namespace {
 class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
   Sema &S;
@@ -1412,6 +1415,119 @@
 }
 
 //===----------------------------------------------------------------------===//
+// -Wconsumed
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace consumed {
+namespace {
+class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
+  
+  Sema &S;
+  DiagList Warnings;
+  
+public:
+  
+  ConsumedWarningsHandler(Sema &S) : S(S) {}
+  
+  void emitDiagnostics() {
+    Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
+    
+    for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
+         I != E; ++I) {
+      
+      const OptionalNotes &Notes = I->second;
+      S.Diag(I->first.first, I->first.second);
+      
+      for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI) {
+        S.Diag(Notes[NoteI].first, Notes[NoteI].second);
+      }
+    }
+  }
+  
+  /// Warn about unnecessary-test errors.
+  /// \param VariableName -- The name of the variable that holds the unique
+  /// value.
+  ///
+  /// \param Loc -- The SourceLocation of the unnecessary test.
+  void warnUnnecessaryTest(StringRef VariableName, StringRef VariableState,
+                           SourceLocation Loc) {
+
+    PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unnecessary_test) <<
+                                 VariableName << VariableState);
+    
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+  }
+  
+  /// Warn about use-while-consumed errors.
+  /// \param MethodName -- The name of the method that was incorrectly
+  /// invoked.
+  /// 
+  /// \param VariableName -- The name of the variable that holds the unique
+  /// value.
+  ///
+  /// \param Loc -- The SourceLocation of the method invocation.
+  void warnUseOfTempWhileConsumed(StringRef MethodName, SourceLocation Loc) {
+                                                    
+    PartialDiagnosticAt Warning(Loc, S.PDiag(
+      diag::warn_use_of_temp_while_consumed) << MethodName);
+    
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+  }
+  
+  /// Warn about use-in-unknown-state errors.
+  /// \param MethodName -- The name of the method that was incorrectly
+  /// invoked.
+  ///
+  /// \param VariableName -- The name of the variable that holds the unique
+  /// value.
+  ///
+  /// \param Loc -- The SourceLocation of the method invocation.
+  void warnUseOfTempInUnknownState(StringRef MethodName, SourceLocation Loc) {
+  
+    PartialDiagnosticAt Warning(Loc, S.PDiag(
+      diag::warn_use_of_temp_in_unknown_state) << MethodName);
+    
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+  }
+  
+  /// Warn about use-while-consumed errors.
+  /// \param MethodName -- The name of the method that was incorrectly
+  /// invoked.
+  ///
+  /// \param VariableName -- The name of the variable that holds the unique
+  /// value.
+  ///
+  /// \param Loc -- The SourceLocation of the method invocation.
+  void warnUseWhileConsumed(StringRef MethodName, StringRef VariableName,
+                            SourceLocation Loc) {
+  
+    PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_while_consumed) <<
+                                MethodName << VariableName);
+    
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+  }
+  
+  /// Warn about use-in-unknown-state errors.
+  /// \param MethodName -- The name of the method that was incorrectly
+  /// invoked.
+  ///
+  /// \param VariableName -- The name of the variable that holds the unique
+  /// value.
+  ///
+  /// \param Loc -- The SourceLocation of the method invocation.
+  void warnUseInUnknownState(StringRef MethodName, StringRef VariableName,
+                             SourceLocation Loc) {
+
+    PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_unknown_state) <<
+                                MethodName << VariableName);
+    
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+  }
+};
+}}}
+
+//===----------------------------------------------------------------------===//
 // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
 //  warnings on a function, method, or block.
 //===----------------------------------------------------------------------===//
@@ -1420,6 +1536,7 @@
   enableCheckFallThrough = 1;
   enableCheckUnreachable = 0;
   enableThreadSafetyAnalysis = 0;
+  enableConsumedAnalysis = 0;
 }
 
 clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
@@ -1440,6 +1557,7 @@
   DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
     (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
      DiagnosticsEngine::Ignored);
+  DefaultPolicy.enableConsumedAnalysis = consumed::checkEnabled(D);
 
 }
 
@@ -1501,7 +1619,8 @@
   // prototyping, but we need a way for analyses to say what expressions they
   // expect to always be CFGElements and then fill in the BuildOptions
   // appropriately.  This is essentially a layering violation.
-  if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis) {
+  if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
+      P.enableConsumedAnalysis) {
     // Unreachable code analysis and thread safety require a linearized CFG.
     AC.getCFGBuildOptions().setAllAlwaysAdd();
   }
@@ -1605,6 +1724,13 @@
     Reporter.emitDiagnostics();
   }
 
+  // Check for violations of consumed properties.
+  if (P.enableConsumedAnalysis) {
+    consumed::ConsumedWarningsHandler WarningHandler(S);
+    consumed::ConsumedAnalyzer Analyzer(S, WarningHandler);
+    Analyzer.run(AC);
+  }
+
   if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
       != DiagnosticsEngine::Ignored ||
       Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index cae855e..77b242d 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -997,6 +997,69 @@
                                Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleConsumesAttr(Sema &S, Decl *D,
+                               const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+  if (!checkAttributeNumArgs(S, Attr, 0)) return;
+
+  if (!(isa<CXXMethodDecl>(D) || isa<CXXConstructorDecl>(D))) {
+    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<
+      Attr.getName();
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             ConsumesAttr(Attr.getRange(), S.Context,
+              Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D,
+                                             const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+  if (!checkAttributeNumArgs(S, Attr, 0)) return;
+
+  if (!isa<CXXMethodDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<
+      Attr.getName();
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             CallableWhenUnconsumedAttr(Attr.getRange(), S.Context,
+              Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleTestsConsumedAttr(Sema &S, Decl *D,
+                                    const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+  if (!checkAttributeNumArgs(S, Attr, 0)) return;
+
+  if (!isa<CXXMethodDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<
+      Attr.getName();
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             TestsConsumedAttr(Attr.getRange(), S.Context,
+              Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleTestsUnconsumedAttr(Sema &S, Decl *D,
+                                      const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+  if (!checkAttributeNumArgs(S, Attr, 0)) return;
+
+  if (!isa<CXXMethodDecl>(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<
+      Attr.getName();
+    return;
+  }
+  
+  D->addAttr(::new (S.Context)
+             TestsUnconsumedAttr(Attr.getRange(), S.Context,
+              Attr.getAttributeSpellingListIndex()));
+}
 
 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
                                     const AttributeList &Attr) {
@@ -4952,6 +5015,20 @@
     handleAcquiredAfterAttr(S, D, Attr);
     break;
 
+  // Uniqueness analysis attributes.
+  case AttributeList::AT_Consumes:
+    handleConsumesAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_CallableWhenUnconsumed:
+    handleCallableWhenUnconsumedAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_TestsConsumed:
+    handleTestsConsumedAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_TestsUnconsumed:
+    handleTestsUnconsumedAttr(S, D, Attr);
+    break;
+
   // Type safety attributes.
   case AttributeList::AT_ArgumentWithTypeTag:
     handleArgumentWithTypeTagAttr(S, D, Attr);