浏览代码

Detect unused variables

Ben Boeckel 15 年之前
父节点
当前提交
e141bc950a
共有 2 个文件被更改,包括 69 次插入2 次删除
  1. 63 2
      Source/cmMakefile.cxx
  2. 6 0
      Source/cmMakefile.h

+ 63 - 2
Source/cmMakefile.cxx

@@ -44,6 +44,7 @@ class cmMakefile::Internals
 public:
   std::stack<cmDefinitions, std::list<cmDefinitions> > VarStack;
   std::stack<std::set<cmStdString> > VarInitStack;
+  std::stack<std::set<cmStdString> > VarUsageStack;
   std::set<cmStdString> VarRemoved;
 };
 
@@ -91,6 +92,8 @@ cmMakefile::cmMakefile(): Internal(new Internals)
   this->AddDefaultDefinitions();
   this->Initialize();
   this->PreOrder = false;
+  this->FindUnused = false;
+  this->DefaultToUsed = false;
 }
 
 cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals)
@@ -133,6 +136,8 @@ cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals)
   this->SubDirectoryOrder = mf.SubDirectoryOrder;
   this->Properties = mf.Properties;
   this->PreOrder = mf.PreOrder;
+  this->FindUnused = mf.FindUnused;
+  this->DefaultToUsed = mf.DefaultToUsed;
   this->ListFileStack = mf.ListFileStack;
   this->Initialize();
 }
@@ -757,6 +762,21 @@ void cmMakefile::SetLocalGenerator(cmLocalGenerator* lg)
   this->AddSourceGroup("Resources", "\\.plist$");
 #endif
 
+  if (this->Internal->VarUsageStack.empty())
+    {
+    const cmDefinitions& defs = cmDefinitions();
+    const std::set<cmStdString> globalKeys = defs.LocalKeys();
+    this->FindUnused = this->GetCMakeInstance()->GetFindUnused();
+    this->DefaultToUsed = this->GetCMakeInstance()->GetDefaultToUsed();
+    if (this->FindUnused)
+      {
+      this->Internal->VarUsageStack.push(globalKeys);
+      }
+    else
+      {
+      this->Internal->VarUsageStack.push(std::set<cmStdString>());
+      }
+    }
 }
 
 bool cmMakefile::NeedBackwardsCompatibility(unsigned int major,
@@ -1690,6 +1710,10 @@ void cmMakefile::AddDefinition(const char* name, bool value)
 {
   this->Internal->VarStack.top().Set(name, value? "ON" : "OFF");
   this->Internal->VarInitStack.top().insert(name);
+  if (this->FindUnused && this->DefaultToUsed)
+    {
+    this->Internal->VarUsageStack.top().insert(name);
+    }
 #ifdef CMAKE_BUILD_WITH_CMAKE
   cmVariableWatch* vv = this->GetVariableWatch();
   if ( vv )
@@ -1709,6 +1733,15 @@ bool cmMakefile::VariableInitialized(const char* var) const
   return false;
 }
 
+bool cmMakefile::VariableUsed(const char* var) const
+{
+  if(this->Internal->VarUsageStack.top().find(var) != this->Internal->VarUsageStack.top().end())
+    {
+    return true;
+    }
+  return false;
+}
+
 bool cmMakefile::VariableCleared(const char* var) const
 {
   if(this->Internal->VarRemoved.find(var) != this->Internal->VarRemoved.end())
@@ -1723,6 +1756,10 @@ void cmMakefile::RemoveDefinition(const char* name)
   this->Internal->VarStack.top().Set(name, 0);
   this->Internal->VarRemoved.insert(name);
   this->Internal->VarInitStack.top().insert(name);
+  if (this->FindUnused)
+    {
+    this->Internal->VarUsageStack.top().insert(name);
+    }
 #ifdef CMAKE_BUILD_WITH_CMAKE
   cmVariableWatch* vv = this->GetVariableWatch();
   if ( vv )
@@ -2101,6 +2138,10 @@ const char* cmMakefile::GetDefinition(const char* name) const
       RecordPropertyAccess(name,cmProperty::VARIABLE);
     }
 #endif
+  if (this->FindUnused)
+    {
+    this->Internal->VarUsageStack.top().insert(name);
+    }
   const char* def = this->Internal->VarStack.top().Get(name);
   if(!def)
     {
@@ -3332,29 +3373,49 @@ void cmMakefile::PushScope()
 {
   cmDefinitions* parent = &this->Internal->VarStack.top();
   const std::set<cmStdString>& init = this->Internal->VarInitStack.top();
+  const std::set<cmStdString>& usage = this->Internal->VarUsageStack.top();
   this->Internal->VarStack.push(cmDefinitions(parent));
   this->Internal->VarInitStack.push(init);
+  this->Internal->VarUsageStack.push(usage);
 }
 
 void cmMakefile::PopScope()
 {
   cmDefinitions* current = &this->Internal->VarStack.top();
   std::set<cmStdString> init = this->Internal->VarInitStack.top();
+  std::set<cmStdString> usage = this->Internal->VarUsageStack.top();
   const std::set<cmStdString>& locals = current->LocalKeys();
-  // Remove initialization information for variables in the local scope.
+  // Remove initialization and usage information for variables in the local
+  // scope.
   std::set<cmStdString>::const_iterator it = locals.begin();
   for (; it != locals.end(); ++it)
     {
     init.erase(*it);
+    if (this->FindUnused && usage.find(*it) == usage.end())
+      {
+      cmOStringStream m;
+      m << "unused variable \'" << *it << "\'";
+      this->IssueMessage(cmake::AUTHOR_WARNING, m.str());
+      }
+    else
+      {
+      usage.erase(*it);
+      }
     }
   this->Internal->VarStack.pop();
   this->Internal->VarInitStack.pop();
-  // Push initialization up to the parent scope.
+  this->Internal->VarUsageStack.pop();
+  // Push initialization and usage up to the parent scope.
   it = init.begin();
   for (; it != init.end(); ++it)
     {
     this->Internal->VarInitStack.top().insert(*it);
     }
+  it = usage.begin();
+  for (; it != usage.end(); ++it)
+    {
+    this->Internal->VarUsageStack.top().insert(*it);
+    }
 }
 
 void cmMakefile::RaiseScope(const char *var, const char *varDef)

+ 6 - 0
Source/cmMakefile.h

@@ -63,6 +63,8 @@ public:
 
   /* return true if a variable has been initialized */
   bool VariableInitialized(const char* ) const;
+  /* return true if a variable has been used */
+  bool VariableUsed(const char* ) const;
   /* return true if a variable has been set with
      set(foo )
   */
@@ -931,6 +933,10 @@ private:
   // should this makefile be processed before or after processing the parent
   bool PreOrder;
 
+  // Unused variable flags
+  bool FindUnused;
+  bool DefaultToUsed;
+
   // stack of list files being read 
   std::deque<cmStdString> ListFileStack;