/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "slang_rs_check_ast.h"

#include "slang_assert.h"
#include "slang_rs.h"
#include "slang_rs_export_foreach.h"
#include "slang_rs_export_type.h"

namespace slang {

void RSCheckAST::VisitStmt(clang::Stmt *S) {
  // This function does the actual iteration through all sub-Stmt's within
  // a given Stmt. Note that this function is skipped by all of the other
  // Visit* functions if we have already found a higher-level match.
  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
       I != E;
       I++) {
    if (clang::Stmt *Child = *I) {
      Visit(Child);
    }
  }
}

void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
  if (!FD) {
    return;
  }

  if (mIsFilterscript) {
    // Validate parameters for Filterscript.
    size_t numParams = FD->getNumParams();

    clang::QualType resultType = FD->getResultType().getCanonicalType();

    // We use FD as our NamedDecl in the case of a bad return type.
    if (!RSExportType::ValidateType(C, resultType, FD,
                                    FD->getLocStart(), mTargetAPI,
                                    mIsFilterscript)) {
      mValid = false;
    }

    for (size_t i = 0; i < numParams; i++) {
      clang::ParmVarDecl *PVD = FD->getParamDecl(i);
      clang::QualType QT = PVD->getType().getCanonicalType();
      if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(),
                                      mTargetAPI, mIsFilterscript)) {
        mValid = false;
      }
    }
  }

  bool saveKernel = mInKernel;
  mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, &mDiagEngine, FD);

  if (clang::Stmt *Body = FD->getBody()) {
    Visit(Body);
  }

  mInKernel = saveKernel;
}


void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
  if (!VD) {
    return;
  }

  clang::QualType QT = VD->getType();

  if (VD->getFormalLinkage() == clang::ExternalLinkage) {
    llvm::StringRef TypeName;
    const clang::Type *T = QT.getTypePtr();
    if (!RSExportType::NormalizeType(T, TypeName, &mDiagEngine, VD)) {
      mValid = false;
    }
  }

  // We don't allow static (non-const) variables within kernels.
  if (mInKernel && VD->isStaticLocal()) {
    if (!QT.isConstQualified()) {
      mDiagEngine.Report(
        clang::FullSourceLoc(VD->getLocation(), mSM),
        mDiagEngine.getCustomDiagID(
          clang::DiagnosticsEngine::Error,
          "Non-const static variables are not allowed in kernels: '%0'"))
          << VD->getName();
      mValid = false;
    }
  }

  if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) {
    mValid = false;
  } else if (clang::Expr *Init = VD->getInit()) {
    // Only check the initializer if the decl is already ok.
    Visit(Init);
  }
}


void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
  if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
    for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
                                        E = DS->decl_end();
         I != E;
         ++I) {
      if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
        ValidateVarDecl(VD);
      } else if (clang::FunctionDecl *FD =
            llvm::dyn_cast<clang::FunctionDecl>(*I)) {
        ValidateFunctionDecl(FD);
      }
    }
  }
}


void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) {
  if (CE->getCastKind() == clang::CK_BitCast) {
    clang::QualType QT = CE->getType();
    const clang::Type *T = QT.getTypePtr();
    if (T->isVectorType()) {
      clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
      if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
        DiagEngine.Report(
          clang::FullSourceLoc(CE->getExprLoc(),
                               DiagEngine.getSourceManager()),
          DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
                                     "invalid implicit vector cast"));
      } else {
        DiagEngine.Report(
          clang::FullSourceLoc(CE->getExprLoc(),
                               DiagEngine.getSourceManager()),
          DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
                                     "invalid vector cast"));
      }
      mValid = false;
    }
  }
  Visit(CE->getSubExpr());
}


void RSCheckAST::VisitExpr(clang::Expr *E) {
  // This is where FS checks for code using pointer and/or 64-bit expressions
  // (i.e. things like casts).

  // First we skip implicit casts (things like function calls and explicit
  // array accesses rely heavily on them and they are valid.
  E = E->IgnoreImpCasts();
  if (mIsFilterscript &&
      !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
      !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(),
                                  mTargetAPI, mIsFilterscript)) {
    mValid = false;
  } else {
    // Only visit sub-expressions if we haven't already seen a violation.
    VisitStmt(E);
  }
}


bool RSCheckAST::Validate() {
  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
  for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
          DE = TUDecl->decls_end();
       DI != DE;
       DI++) {
    if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
      if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
        ValidateVarDecl(VD);
      } else if (clang::FunctionDecl *FD =
            llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
        ValidateFunctionDecl(FD);
      } else if (clang::Stmt *Body = (*DI)->getBody()) {
        Visit(Body);
      }
    }
  }

  return mValid;
}

}  // namespace slang
