move objc expr sema to its own file.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45597 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/SemaExprObjC.cpp b/Sema/SemaExprObjC.cpp
new file mode 100644
index 0000000..e976876
--- /dev/null
+++ b/Sema/SemaExprObjC.cpp
@@ -0,0 +1,295 @@
+//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for Objective-C expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+using namespace clang;
+
+Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
+ ExprTy **Strings,
+ unsigned NumStrings) {
+ SourceLocation AtLoc = AtLocs[0];
+ StringLiteral* S = static_cast<StringLiteral *>(Strings[0]);
+ if (NumStrings > 1) {
+ // Concatenate objc strings.
+ StringLiteral* ES = static_cast<StringLiteral *>(Strings[NumStrings-1]);
+ SourceLocation EndLoc = ES->getSourceRange().getEnd();
+ unsigned Length = 0;
+ for (unsigned i = 0; i < NumStrings; i++)
+ Length += static_cast<StringLiteral *>(Strings[i])->getByteLength();
+ char *strBuf = new char [Length];
+ char *p = strBuf;
+ bool isWide = false;
+ for (unsigned i = 0; i < NumStrings; i++) {
+ S = static_cast<StringLiteral *>(Strings[i]);
+ if (S->isWide())
+ isWide = true;
+ memcpy(p, S->getStrData(), S->getByteLength());
+ p += S->getByteLength();
+ delete S;
+ }
+ S = new StringLiteral(strBuf, Length,
+ isWide, Context.getPointerType(Context.CharTy),
+ AtLoc, EndLoc);
+ }
+
+ if (CheckBuiltinCFStringArgument(S))
+ return true;
+
+ if (Context.getObjcConstantStringInterface().isNull()) {
+ // Initialize the constant string interface lazily. This assumes
+ // the NSConstantString interface is seen in this translation unit.
+ IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString");
+ ScopedDecl *IFace = LookupScopedDecl(NSIdent, Decl::IDNS_Ordinary,
+ SourceLocation(), TUScope);
+ ObjcInterfaceDecl *strIFace = dyn_cast_or_null<ObjcInterfaceDecl>(IFace);
+ if (!strIFace)
+ return Diag(S->getLocStart(), diag::err_undef_interface,
+ NSIdent->getName());
+ Context.setObjcConstantStringInterface(strIFace);
+ }
+ QualType t = Context.getObjcConstantStringInterface();
+ t = Context.getPointerType(t);
+ return new ObjCStringLiteral(S, t, AtLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
+ SourceLocation EncodeLoc,
+ SourceLocation LParenLoc,
+ TypeTy *Ty,
+ SourceLocation RParenLoc) {
+ QualType EncodedType = QualType::getFromOpaquePtr(Ty);
+
+ QualType t = Context.getPointerType(Context.CharTy);
+ return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
+ SourceLocation AtLoc,
+ SourceLocation SelLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ QualType t = Context.getObjcSelType();
+ return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ ObjcProtocolDecl* PDecl = ObjcProtocols[ProtocolId];
+ if (!PDecl) {
+ Diag(ProtoLoc, diag::err_undeclared_protocol, ProtocolId->getName());
+ return true;
+ }
+
+ QualType t = Context.getObjcProtoType();
+ if (t.isNull())
+ return true;
+ t = Context.getPointerType(t);
+ return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc);
+}
+
+bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+ ObjcMethodDecl *Method) {
+ bool anyIncompatibleArgs = false;
+
+ for (unsigned i = 0; i < NumArgs; i++) {
+ Expr *argExpr = Args[i];
+ assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+
+ QualType lhsType = Method->getParamDecl(i)->getType();
+ QualType rhsType = argExpr->getType();
+
+ // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
+ if (const ArrayType *ary = lhsType->getAsArrayType())
+ lhsType = Context.getPointerType(ary->getElementType());
+ else if (lhsType->isFunctionType())
+ lhsType = Context.getPointerType(lhsType);
+
+ AssignConvertType Result = CheckSingleAssignmentConstraints(lhsType,
+ argExpr);
+ if (Args[i] != argExpr) // The expression was converted.
+ Args[i] = argExpr; // Make sure we store the converted expression.
+
+ anyIncompatibleArgs |=
+ DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
+ argExpr, "sending");
+ }
+ return anyIncompatibleArgs;
+}
+
+// ActOnClassMessage - used for both unary and keyword messages.
+// ArgExprs is optional - if it is present, the number of expressions
+// is obtained from Sel.getNumArgs().
+Sema::ExprResult Sema::ActOnClassMessage(
+ Scope *S,
+ IdentifierInfo *receiverName, Selector Sel,
+ SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs)
+{
+ assert(receiverName && "missing receiver class name");
+
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ ObjcInterfaceDecl* ClassDecl = 0;
+ if (!strcmp(receiverName->getName(), "super") && CurMethodDecl) {
+ ClassDecl = CurMethodDecl->getClassInterface()->getSuperClass();
+ if (ClassDecl && CurMethodDecl->isInstance()) {
+ // Synthesize a cast to the super class. This hack allows us to loosely
+ // represent super without creating a special expression node.
+ IdentifierInfo &II = Context.Idents.get("self");
+ ExprResult ReceiverExpr = ActOnIdentifierExpr(S, lbrac, II, false);
+ QualType superTy = Context.getObjcInterfaceType(ClassDecl);
+ superTy = Context.getPointerType(superTy);
+ ReceiverExpr = ActOnCastExpr(SourceLocation(), superTy.getAsOpaquePtr(),
+ SourceLocation(), ReceiverExpr.Val);
+ // We are really in an instance method, redirect.
+ return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac,
+ Args, NumArgs);
+ }
+ // We are sending a message to 'super' within a class method. Do nothing,
+ // the receiver will pass through as 'super' (how convenient:-).
+ } else
+ ClassDecl = getObjCInterfaceDecl(receiverName);
+
+ // FIXME: can ClassDecl ever be null?
+ ObjcMethodDecl *Method = ClassDecl->lookupClassMethod(Sel);
+ QualType returnType;
+
+ // Before we give up, check if the selector is an instance method.
+ if (!Method)
+ Method = ClassDecl->lookupInstanceMethod(Sel);
+ if (!Method) {
+ Diag(lbrac, diag::warn_method_not_found, std::string("+"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ returnType = Context.getObjcIdType();
+ } else {
+ returnType = Method->getResultType();
+ if (Sel.getNumArgs()) {
+ if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+ return true;
+ }
+ }
+ return new ObjCMessageExpr(receiverName, Sel, returnType, Method,
+ lbrac, rbrac, ArgExprs, NumArgs);
+}
+
+// ActOnInstanceMessage - used for both unary and keyword messages.
+// ArgExprs is optional - if it is present, the number of expressions
+// is obtained from Sel.getNumArgs().
+Sema::ExprResult Sema::ActOnInstanceMessage(
+ ExprTy *receiver, Selector Sel,
+ SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs)
+{
+ assert(receiver && "missing receiver expression");
+
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ Expr *RExpr = static_cast<Expr *>(receiver);
+ QualType receiverType = RExpr->getType();
+ QualType returnType;
+ ObjcMethodDecl *Method = 0;
+
+ if (receiverType == Context.getObjcIdType() ||
+ receiverType == Context.getObjcClassType()) {
+ Method = InstanceMethodPool[Sel].Method;
+ if (!Method)
+ Method = FactoryMethodPool[Sel].Method;
+ if (!Method) {
+ Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ returnType = Context.getObjcIdType();
+ } else {
+ returnType = Method->getResultType();
+ if (Sel.getNumArgs())
+ if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+ return true;
+ }
+ } else {
+ bool receiverIsQualId = dyn_cast<ObjcQualifiedIdType>(receiverType) != 0;
+ // FIXME (snaroff): checking in this code from Patrick. Needs to be
+ // revisited. how do we get the ClassDecl from the receiver expression?
+ if (!receiverIsQualId)
+ while (receiverType->isPointerType()) {
+ PointerType *pointerType =
+ static_cast<PointerType*>(receiverType.getTypePtr());
+ receiverType = pointerType->getPointeeType();
+ }
+ ObjcInterfaceDecl* ClassDecl = 0;
+ if (ObjcQualifiedInterfaceType *QIT =
+ dyn_cast<ObjcQualifiedInterfaceType>(receiverType)) {
+ ClassDecl = QIT->getDecl();
+ Method = ClassDecl->lookupInstanceMethod(Sel);
+ if (!Method) {
+ // search protocols
+ for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
+ ObjcProtocolDecl *PDecl = QIT->getProtocols(i);
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+ break;
+ }
+ }
+ if (!Method)
+ Diag(lbrac, diag::warn_method_not_found_in_protocol,
+ std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ }
+ else if (ObjcQualifiedIdType *QIT =
+ dyn_cast<ObjcQualifiedIdType>(receiverType)) {
+ // search protocols
+ for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
+ ObjcProtocolDecl *PDecl = QIT->getProtocols(i);
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+ break;
+ }
+ if (!Method)
+ Diag(lbrac, diag::warn_method_not_found_in_protocol,
+ std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ }
+ else {
+ assert(ObjcInterfaceType::classof(receiverType.getTypePtr()) &&
+ "bad receiver type");
+ ClassDecl = static_cast<ObjcInterfaceType*>(
+ receiverType.getTypePtr())->getDecl();
+ // FIXME: consider using InstanceMethodPool, since it will be faster
+ // than the following method (which can do *many* linear searches). The
+ // idea is to add class info to InstanceMethodPool...
+ Method = ClassDecl->lookupInstanceMethod(Sel);
+ }
+ if (!Method) {
+ // If we have an implementation in scope, check "private" methods.
+ if (ClassDecl)
+ if (ObjcImplementationDecl *ImpDecl =
+ ObjcImplementations[ClassDecl->getIdentifier()])
+ Method = ImpDecl->getInstanceMethod(Sel);
+ // If we still haven't found a method, look in the global pool. This
+ // behavior isn't very desirable, however we need it for GCC
+ // compatibility.
+ if (!Method)
+ Method = InstanceMethodPool[Sel].Method;
+ }
+ if (!Method) {
+ Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ returnType = Context.getObjcIdType();
+ } else {
+ returnType = Method->getResultType();
+ if (Sel.getNumArgs())
+ if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+ return true;
+ }
+ }
+ return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
+}