summaryrefslogtreecommitdiffstats
path: root/tags/cpp-1.0-incubating-M2-final/sca/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/common/MethodPart.java
blob: a25610c1f93009a24fda9e0866cc0c43916c0c5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
 *
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.
 */

/* @version $Rev$ $Date$ */

/*
 *  Branched from the original class that was also contributed to the 
 *  org.apache.axis.tools.common package.
 */
package org.apache.tuscany.sca.cpp.tools.common;

import java.util.ArrayList;

/**
 * A C or C++ method from a piece of source code. The method has a signature and
 * a body (the bit between the braces).
 */
public class MethodPart extends FilePart {
    private Signature signature;

    private String body;

    MethodPart(String s, Signature signature, String body) {
        super(s, METHOD);
        this.signature = signature;
        this.body = body;
    }

    public Signature getSignature() {
        return signature;
    }

    public String getOriginalSignature() {
        return signature.getOriginal();
    }

    /**
     * Returns the method body as code snippets, each ending with a place where
     * a trace statement belongs. The end of the first code snippet is where the
     * entry trace should go. The end of every other snippet is a return from
     * the method.
     */
    public BodyPart[] getBodyParts() throws ParsingException {
        String b = body; // Don't alter field member
        if (b.startsWith("{"))
            b = b.substring(1);

        // Add in trace exit at all the return statements in the method.
        ArrayList al = new ArrayList();
        int idxR = Utils.indexOf(b, "return");
        int idxC = Utils.indexOf(b, "catch");
        while (-1 != idxR || -1 != idxC) {
            if (-1 == idxC || (-1 != idxR && idxR < idxC)) {
                String frag = b.substring(0, idxR);
                String rest = b.substring(idxR + "return".length());

                int semicolon = Utils.indexOf(rest, ';');
                if (-1 == semicolon)
                    Utils.rude("Missing semicolon in " + signature);
                String retVal = rest.substring(0, semicolon);
                BodyPart bp = new BodyPart(frag, retVal);
                al.add(bp);
                b = b.substring(idxR + "return".length() + retVal.length() + 1);
            } else {
                String frag = b.substring(0, idxC);
                String rest = b.substring(idxC);

                int brace = Utils.indexOf(rest, "{");
                if (-1 == brace)
                    Utils.rude("Missing open brace in " + signature);
                Signature signature = new Signature(rest.substring(0, brace));
                frag = frag + rest.substring(0, brace + 1);
                BodyPart bp = new BodyPart(frag, signature.getParameters()[0]);
                al.add(bp);
                b = rest.substring(brace + 1);
            }
            idxR = Utils.indexOf(b, "return");
            idxC = Utils.indexOf(b, "catch");
        }

        // Add in trace exit before the last } if there are no returns in
        // the method or there is code after the last return and the method
        // returns void.
        // int f1(){try{return f2();}catch(Exception& e){throw;}}
        // has code after the last return but having a traceexit before the
        // last brace wouldn't compile since the method returns an int. We
        // cope with this by only adding in a traceexit before the last brace
        // if the method returns void. That may mean we add in an unreachable
        // traceexit which may give a compiler warning, but that should be
        // benign.
        //
        // TODO: Not quite good enough for
        // void f(int a){if(a){printf("a");}else{printf("!a");return;}}
        // as a trace exit is needed before the last } in case a>0 but
        // void f(int a){if(a){printf("a");return;}else{printf("!a");return;}}
        // would give compiler warnings about unreachable code if a trace
        // exit is added before the last brace. This could be tricky to fix.
        if ((0 == al.size() || -1 != Utils.indexOf(b, ';'))
                && null == signature.getReturnType().getType()) {

            int last = b.lastIndexOf('}');
            if (-1 == last)
                Utils.rude("Missing end brace in " + signature);
            String b2 = b.substring(0, last);
            al.add(new BodyPart(b2));
            b = b.substring(last);
        }

        // The final body part is the last }
        al.add(new BodyPart(b));

        BodyPart[] bps = new BodyPart[al.size()];
        System.arraycopy(al.toArray(), 0, bps, 0, al.size());
        return bps;
    }
}