//
//      Copyright (c) 2023, an unpublished work by CodeSecure, Inc.
//                      ALL RIGHTS RESERVED
//
//      Copyright (c) 2017-2023, an unpublished work by GrammaTech, Inc.
//                      ALL RIGHTS RESERVED
// 
//      This software is furnished under a license and may be used and
//      copied only in accordance with the terms of such license and the
//      inclusion of the above copyright notice.  This software or any
//      other copies thereof may not be provided or otherwise made
//      available to any other person.  Title to and ownership of the
//      software is retained by CodeSecure, Inc.
// 

// UCvar_plugin.cpp
// 
//  A small example plugin that reports declarations for variables
//  whose names contain upper case characters.

// Must precede #include "csonar_api.hpp".
#define CS_CPP_IMPL

// For Visual C++
#define _CRT_SECURE_NO_WARNINGS 1
 
// Include the entire CodeSonar C++ API.
#include "csonar_api.hpp"  
 
// for std::cout
#include <iostream>

// for isupper
#include <cctype>



// The plug-in defines a new warning class to go with its new check. We
// do not associate any CodeSonar mnemonics or CWE identifiers with the
// new class, as none are appropriate.  The new warning class must be
// created either in the top level scope or inside cs_plug_main().

static cs::warningclass upvar_wc = cs::analysis::create_warningclass(
    "Variable name has upper case characters",
    "",
    1.0,
    cs::warningclass_flags::PADDING,
    cs::warning_significance::STYLE
    );


// Visitors should be at the finest granularity that is appropriate
// for the check. This plug-in is checking a property of variable
// names, so we define a visitor that operates on symbols.

class check_var_case: public cs::visitor<cs::symbol>
{
  void operator()(cs::symbol sym){
    std::string nm = sym.name();                   // cs::symbol::name()

    // If there are one or more upper case characters and the variable
    // is declared in user code, issue a warning and return.
    for ( std::string::iterator it=nm.begin(); it!=nm.end(); ++it){
      if (isupper(*it)){
        
        try {
          cs::sfileinst_line_pair symfl = sym.file_line();
          if (!symfl.first.is_system_include()){   // cs::sfileinst::is_system_include()
            upvar_wc.report(symfl.first,
                            symfl.second,
                            "Variable name " + nm + " has upper case character");
            
            return;
          }
        }
        catch( const cs::result &r ){
            // If no position, do not report warning. Rethrow any
            // other cs::result exceptions.
          if (r==cs::result::NO_POSITION) return;
          throw;
        }
      }
    }
  }
};

// Create an instance of check_var_case, and add it as a symbol
// visitor.  Visitors must be added either in the top-level scope or
// in cs_plug_main().
static char dummy = (cs::analysis::add_symbol_visitor(new check_var_case()), 0);    

// Every C++ plug-in for CodeSonar must define this function. 
static void cs_plug_main(void){}


// All CodeSonar C++ plug-ins must finish with a line of this form (at
// the top level). Note that the argument UCvar_plugin to
// CS_DEFINE_PLUGIN corresponds to the name of the compiled plug-in
// (which will be UCvar_plugin.dll, UCvar_plugin.bundle, or
// UCvar_plugin.so, depending on your system).
CS_DEFINE_PLUGIN(UCvar_plugin)
