/** * Called after the creation of any module. Used as a workaround for filling tokens that are in no * way available in the code-completion through the regular inspection. * * <p>The django objects class is the reason why this happens... It's structure for the creation * on a model class follows no real patterns for the creation of the 'objects' attribute in the * class, and thus, we have no real generic way of discovering it (actually, even by looking at * the class definition this is very obscure), so, the solution found is creating the objects by * decorating the module with that info. */ private AbstractModule decorateModule(AbstractModule n, IPythonNature nature) { if (n instanceof SourceModule && "django.db.models.base".equals(n.getName())) { SourceModule sourceModule = (SourceModule) n; SimpleNode ast = sourceModule.getAst(); for (SimpleNode node : ((Module) ast).body) { if (node instanceof ClassDef && "Model".equals(NodeUtils.getRepresentationString(node))) { Object[][] metaclassAttrs = new Object[][] { {"objects", NodeUtils.makeAttribute("django.db.models.manager.Manager()")}, {"DoesNotExist", new Name("Exception", Name.Load, false)}, {"MultipleObjectsReturned", new Name("Exception", Name.Load, false)}, }; ClassDef classDef = (ClassDef) node; stmtType[] newBody = new stmtType[classDef.body.length + metaclassAttrs.length]; System.arraycopy(classDef.body, 0, newBody, metaclassAttrs.length, classDef.body.length); int i = 0; for (Object[] objAndType : metaclassAttrs) { // Note that the line/col is important so that we correctly acknowledge it inside the // "class Model" scope. Name name = new Name((String) objAndType[0], Name.Store, false); name.beginColumn = classDef.beginColumn + 4; name.beginLine = classDef.beginLine + 1; newBody[i] = new Assign(new exprType[] {name}, (exprType) objAndType[1]); newBody[i].beginColumn = classDef.beginColumn + 4; newBody[i].beginLine = classDef.beginLine + 1; i += 1; } classDef.body = newBody; break; } } } return n; }